const { assert } = require("chai");
let JavaScript;

describe("Language", () => {
  before(async () => ({ JavaScript } = await require("./helper")));

  describe(".fieldIdForName, .fieldNameForId", () => {
    it("converts between the string and integer representations of fields", () => {
      const nameId = JavaScript.fieldIdForName("name");
      const bodyId = JavaScript.fieldIdForName("body");

      assert.isBelow(nameId, JavaScript.fieldCount);
      assert.isBelow(bodyId, JavaScript.fieldCount);
      assert.equal("name", JavaScript.fieldNameForId(nameId));
      assert.equal("body", JavaScript.fieldNameForId(bodyId));
    });

    it("handles invalid inputs", () => {
      assert.equal(null, JavaScript.fieldIdForName("namezzz"));
      assert.equal(null, JavaScript.fieldNameForId(-1));
      assert.equal(null, JavaScript.fieldNameForId(10000));
    });
  });

  describe(".idForNodeType, .nodeTypeForId, .nodeTypeIsNamed", () => {
    it("converts between the string and integer representations of a node type", () => {
      const exportStatementId = JavaScript.idForNodeType("export_statement", true);
      const starId = JavaScript.idForNodeType("*", false);

      assert.isBelow(exportStatementId, JavaScript.nodeTypeCount);
      assert.isBelow(starId, JavaScript.nodeTypeCount);
      assert.equal(true, JavaScript.nodeTypeIsNamed(exportStatementId))
      assert.equal("export_statement", JavaScript.nodeTypeForId(exportStatementId))
      assert.equal(false, JavaScript.nodeTypeIsNamed(starId))
      assert.equal("*", JavaScript.nodeTypeForId(starId))
    });

    it("handles invalid inputs", () => {
      assert.equal(null, JavaScript.nodeTypeForId(-1));
      assert.equal(null, JavaScript.nodeTypeForId(10000));
      assert.equal(null, JavaScript.idForNodeType("export_statement", false));
    });
  });
});

describe("Lookahead iterator", () => {
  let lookahead;
  let state;
  before(async () => {
    let Parser;
    ({ JavaScript, Parser } = await require("./helper"));
    const parser = new Parser().setLanguage(JavaScript);
    const tree = parser.parse("function fn() {}");
    parser.delete();
    const cursor = tree.walk();
    assert(cursor.gotoFirstChild());
    assert(cursor.gotoFirstChild());
    state = cursor.currentNode().nextParseState;
    lookahead = JavaScript.lookaheadIterator(state);
    assert.exists(lookahead);
  });

  after(() => {
    lookahead.delete();
  });

  const expected = ["identifier", "comment", "(", "*", "formal_parameters"];
  it("should iterate over valid symbols in the state", () => {
    const symbols = Array.from(lookahead);
    assert.includeMembers(symbols, expected);
    assert.lengthOf(symbols, expected.length);
  });

  it("should reset to the initial state", () => {
    assert(lookahead.resetState(state));
    const symbols = Array.from(lookahead);
    assert.includeMembers(symbols, expected);
    assert.lengthOf(symbols, expected.length);
  });

  it("should reset", () => {
    assert(lookahead.reset(JavaScript, state));
    const symbols = Array.from(lookahead);
    assert.includeMembers(symbols, expected);
    assert.lengthOf(symbols, expected.length);
  });
});
